/**
 * 
 */
package com.jushu.storbox.database;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import android.content.ContentValues;
import android.database.Cursor;

import com.jushu.storbox.ShareDriveApplication;
import com.jushu.storbox.constant.ClientConfig;
import com.jushu.storbox.constant.Constant;
import com.jushu.storbox.database.BaseDao;
import com.jushu.storbox.database.IBaseDao;
import com.jushu.storbox.entities.FileFolderInfo;
import com.jushu.storbox.entities.FileInfo;
import com.jushu.storbox.util.LogUtil;
import com.huawei.sharedrive.sdk.android.modelV2.response.FileInfoResponseV2;

/**
 * File local data access
 */
public class FileDao extends BaseDao implements IFileDao {

	public final static String LOG_TAG = "FileDao";

	/**
	 * 
	 */
	public FileDao() {
	}

	@Override
	public long insertFile(FileInfoResponseV2 fileInfo) {
		long row = -1;
		try {
			FileFolderInfo fileInfoa = getFile(fileInfo.getOwnerBy(), fileInfo.getId());
			if(null != fileInfoa ){
				LogUtil.e(LOG_TAG , "fileDao no need insertFile, id identical");
				return row;
			}
			
			FileInfo tempFileInfo = new FileInfo();
			tempFileInfo.valueOf(fileInfo);
			row = this.getDb().insert(TABLE_NAME, null, tempFileInfo.toContentValues());
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "insertFile fail:" + e.getLocalizedMessage());
		}
		return row;
	}
	
	public long insertFile(FileFolderInfo fileInfo) {
		long row = -1;
		try {
			row = this.getDb().insert(TABLE_NAME, null, fileInfo.toContentValues());
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "insertFile fail:" + e.getLocalizedMessage());
		}
		return row;
	}
	
	public void updateFile(FileInfoResponseV2 fileInfoResponse,
			boolean resetFileDownloadState, boolean syncIdentity) {
		try {
			FileInfo tempFileInfo = getFile(fileInfoResponse.getOwnerBy(), fileInfoResponse.getId());
			if(tempFileInfo == null) {
				tempFileInfo = new FileInfo();
				LogUtil.e(LOG_TAG, "update file infomation use new instanc!");
			}
			tempFileInfo.copyFiledValue(fileInfoResponse);
			ContentValues cv = tempFileInfo.toContentValues();
			if(resetFileDownloadState){
				cv.put(trans_status, Constant.DOWNLOAD_NON_UPDATE_DB);
			} else {
				cv.remove(trans_status);
			}
			
			if(!syncIdentity) {
				cv.remove(file_md5);
				cv.remove(file_sha1);
			}
			
			this.getDb().update(TABLE_NAME, cv, 
					getQueryKey(), getQueryValue(tempFileInfo.getId(), tempFileInfo.getOwnerBy()));
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "updateFile fail:" + e.getLocalizedMessage());
		}
	}
	
	public void updateLocalPath(String ownerId, String fileId, String localPath) {
		try {
			if (null != fileId) {
				ContentValues cv = new ContentValues();
				cv.put(local_path,localPath);
				this.getDb().update(TABLE_NAME, cv, getQueryKey(), getQueryValue(fileId , ownerId));
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "updateLocalPath is fail:" + e.getLocalizedMessage());
		}
	}
	
	public void updateLocalPath(FileFolderInfo file, String localPath) {
		updateLocalPath(file.getOwnerId(), file.getId(), localPath);
	}
	
	public void updateLocalPath(FileInfoResponseV2 serverFile, String localPath) {
		updateLocalPath(serverFile.getOwnerBy(), serverFile.getId(), localPath);
	}
	
	public void updateTransStatus(FileFolderInfo file, int status) {
		updateTransStatus(file.getOwnerId(), file.getId(), status);
	}
	public void updateTransStatus(FileInfoResponseV2 serverFile, int status) {
		updateTransStatus(serverFile.getOwnerBy(), serverFile.getId(), status);
	}
	
	public void updateFileIdentify(FileFolderInfo file, String identify) {
		try {
			if (null != file.getId()) {
				ContentValues cv = new ContentValues();
				cv.put(file_md5, identify);
				this.getDb().update(IFileDao.TABLE_NAME, cv, 
						getQueryKey(), getQueryValue(file.getId(), file.getOwnerId()));
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "updateFileIdentify is fail:" + e.getLocalizedMessage());
		}
		
	}
	
	public int getTransStatus(FileFolderInfo file) {
		int transStatus = -1;
		try {
			if (null != file.getId()) {
				String sql = "select  " + trans_status + " from " + TABLE_NAME 
						+ " where "+ getQueryKey();
				Cursor cursor = this.getDb().rawQuery(sql, getQueryValue(file.getId() ,file.getOwnerId()));
				if (cursor.moveToFirst()) {
					transStatus = cursor.getInt(0);
				}
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "getTransStatus fail:" + e.getLocalizedMessage());
		}
		return transStatus;
	}
	
	public void updateSyncStatus(FileInfoResponseV2 serverNode, int syncStatus) {
		updateSyncStatus(serverNode.getOwnerBy(), serverNode.getId() ,syncStatus);
	}
	
	public void updateSyncStatus(String ownerId, String fileId, int syncStatus) {
		try {
			ContentValues cv = new ContentValues();
			cv.put(isSync, syncStatus);
			this.getDb().update(TABLE_NAME, cv, getQueryKey(), getQueryValue(fileId ,ownerId));
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "updateSyncStatus is fail:" + e.getLocalizedMessage());
		}
	}
	
	public void updateSyncStatus(FileFolderInfo file, int syncStatus) {
		updateSyncStatus(file.getOwnerId(), file.getId() ,syncStatus);
	}
	
	public long getLastUpdateTime(FileFolderInfo file) {
		long lastUpdateTime = 0;
		try {
			if (null != file.getId()) {
				Cursor cursor = this.getDb().rawQuery(
						"select * from  " + TABLE_NAME + " where "+ getQueryKey(),
						getQueryValue(file.getId() ,file.getOwnerId()));
				if (cursor.moveToFirst()) {
					lastUpdateTime = cursor.getInt(cursor
							.getColumnIndex(local_last_modify_time));
				}
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "getLastUpdateTime is fail:" + e.getLocalizedMessage());
		}
		
		return lastUpdateTime;
	}
	
	public void updateLastUpdateTime(FileFolderInfo file) {
		try {
			if (null != file.getId()) {
				ContentValues cv = new ContentValues();
				cv.put(local_last_modify_time, Calendar.getInstance().getTimeInMillis());
				this.getDb().update(TABLE_NAME, cv , getQueryKey(), getQueryValue(file.getId(), file.getOwnerId()));
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "updateLastUpdateTime is fail:" + e.getLocalizedMessage());
		}
	}
	
	public void updateLocalSaveState(FileFolderInfo file) {
		try {
			if (null != file.getId()) {
				this.getDb().update(TABLE_NAME, file.getSyncStateCV() , getQueryKey(), 
						getQueryValue(file.getId(), file.getOwnerId()));
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "updateLastUpdateTime is fail:" + e.getLocalizedMessage());
		}
	}
	
	public void rename(FileFolderInfo file, String name) {
		rename(file.getOwnerBy(), file.getId(), file.getModifiedAt(), name );
	}
	
	public void move(FileFolderInfo file, FileFolderInfo folder) {
		try {
			if (null != file.getId()) {
				ContentValues cv = new ContentValues();
				cv.put(parent_folder_id, folder.getId());
				this.getDb().update(TABLE_NAME, cv , getQueryKey(), getQueryValue(file.getId(), file.getOwnerId()));
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "moveFile is fail:" + e.getLocalizedMessage());
		}
	}
	
	public void delete(FileFolderInfo file) {
		try {
			if (null != file.getId()) {
				this.getDb().execSQL("delete from " + TABLE_NAME + " where " + getQueryKey(),
						getQueryValue(file.getId(), file.getOwnerId()));
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "deleteFile is fail:" + e.getLocalizedMessage());
		}
	}
	
	public void deleteAll() {
		try {
			String whereClause = IFileDao.CURRENT_USER_ID + " = ?";
			String[] whereArgs = {getCurrentUserId()};
			this.getDb().delete(TABLE_NAME, whereClause, whereArgs);
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "deleteAll is fail:" + e.getLocalizedMessage());
		}
	}
	
	public void setShareLink(FileFolderInfo file, boolean isShareLink) {
        try {
            ContentValues cv = new ContentValues();
            cv.put(isshare_link, isShareLink);
            this.getDb().update(TABLE_NAME, cv, getQueryKey(), getQueryValue(file.getId() ,file.getOwnerId()));
        } catch (Exception e) {
            LogUtil.e(LOG_TAG, "updateSyncStatus is fail:" + e.getLocalizedMessage());
        }
    }
	
	public void cleanCatch(){
		try {
			ContentValues values = new ContentValues();
			values.put(local_path, "");
			values.put(trans_status, Constant.DOWNLOAD_NON_UPDATE_DB);
			values.put(isSync, Constant.DOWNLOAD_STATUS_NOCACHE_DB);
			String whereClause = IFileDao.CURRENT_USER_ID + " = ?";
			String[] whereArgs = {getCurrentUserId()};
			this.getDb().update(TABLE_NAME, values, whereClause, whereArgs);
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "deleteAll is fail:" + e.getLocalizedMessage());
		}
	}

	public int addIfNotExist(FileInfoResponseV2 fileInfo) {
		try {
			FileFolderInfo localFileInfo = getFile(fileInfo.getOwnerBy(), fileInfo.getId());
			if(null != localFileInfo){
				LogUtil.e(LOG_TAG , "fileDao need not insertFile, id identical");
				return 0;
			}
			FileInfo tempInfo = new FileInfo();
			tempInfo.valueOf(fileInfo);
			this.getDb().insert(TABLE_NAME, null, tempInfo.toContentValues());
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "insertFile fail:" + e.getLocalizedMessage());
		}
		return 1;
	}
	
	public FileInfo getFile(FileInfoResponseV2 serverNode) {
		return getFile(serverNode.getOwnerBy(), serverNode.getId());
	}
	
	public FileInfo getFile(FileFolderInfo serverNode) {
		return getFile(serverNode.getOwnerBy(), serverNode.getId());
	}
	
	public FileInfo getFile(String ownerId, String fileId) {
		FileInfo fileInfo = null;
		try {
			if (null != fileId) {
				Cursor cursor = this.getDb().rawQuery(
						"select * from " + TABLE_NAME + "  where " +getQueryKey(),
						getQueryValue(fileId, ownerId));
				if (cursor.moveToFirst()) {
					fileInfo = new FileInfo();
					fileInfo.fromCursor(cursor);
				}
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "getFileById is fail:" + e.getLocalizedMessage());
		}
		return fileInfo;
	}
	
	public List<FileInfo> getFileList(FileFolderInfo folder) {
		return getFileList(folder.getOwnerId(), folder.getId());
	}
	
	public List<FileInfo> getFileListPage(String ownerId, String folderId, int flag) {
		if (null != folderId) {
			int number = ClientConfig.CLOUD_COUNT_PER_PAGE;
			int count = ShareDriveApplication.getInstance()
					.getMyCloudDrivePage() * number;
			if (Constant.SHARED_GET_FILE_LIST_STATE == flag) {
				number = ClientConfig.SHARED_COUNT_PER_PAGE;//
				count = ShareDriveApplication.getInstance().getMySharePage()
						* number;
			}

			List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
			try {
				String strSQL = "select * from " + TABLE_NAME + " where "
								+ getSubCollectQueryKey()
								+ " Order by server_mtime desc" + " limit ?"
								+ " offset ?" ;
				String[] selectionArgs = new String[] { folderId, ownerId, getCurrentUserId(),
						String.valueOf(number), String.valueOf(count)};
				
				Cursor cursor = this.getDb().rawQuery(strSQL,selectionArgs);
				if (!cursor.moveToFirst()) {
					return fileInfoList;
				}
				do {
					FileInfo fileInfo = new FileInfo();
					fileInfo.fromCursor(cursor);
					fileInfoList.add(fileInfo);
				} while (cursor.moveToNext());
			} catch (Exception e) {
				LogUtil.e(LOG_TAG, "getFileListPage is fail:" + e.getLocalizedMessage());
			}
			
			return fileInfoList;
		} else {
			LogUtil.e(LOG_TAG, "getFileListPage folderId is null");
		}
		return null;
	}
	
	public List<FileInfo> getFileListByPage(String ownerId, String folderId, int pageNo, int number, String des, String orderBy) {
		String dbDes = "desc";
		String dbOrderBy = "server_mtime";
		if ("DESC".equals(des)) {
			dbDes = "desc";
		} else {
			dbDes = "asc";
		}
		if ("size".equals(orderBy)) {
			dbOrderBy = file_size;
		} else if ("name".equals(orderBy)) {
			dbOrderBy = file_name;
		} else {
			dbOrderBy = server_mtime;
		}
		if (null != folderId) {
			int offset = (pageNo -1) * ClientConfig.CLOUD_COUNT_PER_PAGE;
			
			List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
			try {
				
				String strSQL = "select * from " + TABLE_NAME;
				
				if("name".equals(orderBy))
				{
					strSQL = "select * from " + TABLE_NAME + " where "
							+ getSubCollectQueryKey()
							+" Order by "+ dbOrderBy + " collate nocase " + dbDes 
							+ " limit ?" + " offset ?";
				}else{
					strSQL = "select * from " + TABLE_NAME + " where "
							+ getSubCollectQueryKey()
							+" Order by " + dbOrderBy + " " + dbDes + " limit ?"
							+ " offset ?";
				}
				Cursor cursor = this.getDb().rawQuery(strSQL,
						new String[] { 
						folderId, ownerId, getCurrentUserId(),
						String.valueOf(number),
						String.valueOf(offset)});
				if (!cursor.moveToFirst()) {
					return fileInfoList;
				}
				do {
					FileInfo fileInfo = new FileInfo();
					fileInfo.fromCursor(cursor);
					fileInfoList.add(fileInfo);
				} while (cursor.moveToNext());
			} catch (Exception e) {
				LogUtil.e(LOG_TAG, "getFileListPage is fail:" + e.getLocalizedMessage());
			}
			return fileInfoList;
		} else {
			LogUtil.e(LOG_TAG, "folderId is null");
		}
		return null;
	}

	public List<FileInfo> getFileListPage(String ownerId, String folderId,int flag,
			String des, String orderBy) {
		String dbDes = "desc";
		String dbOrderBy = "server_mtime";
		if ("DESC".equals(des)) {
			dbDes = "desc";
		} else {
			dbDes = "asc";
		}
		if ("size".equals(orderBy)) {
			dbOrderBy = file_size;
		} else if ("name".equals(orderBy)) {
			dbOrderBy = file_name;
		} else {
			dbOrderBy = server_mtime;
		}
		if (null != folderId) {
			int number = ClientConfig.CLOUD_COUNT_PER_PAGE;
			int count = ShareDriveApplication.getInstance()
					.getMyCloudDrivePage() * number;
			if (Constant.SHARED_GET_FILE_LIST_STATE == flag) {
				number = ClientConfig.SHARED_COUNT_PER_PAGE;//
				count = ShareDriveApplication.getInstance().getMySharePage()
						* number;
			}
			List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
			try {
				String strSQL = "select * from " + TABLE_NAME;
				
				if("name".equals(orderBy))
				{
					strSQL = "select * from " + TABLE_NAME + " where "
							+ getSubCollectQueryKey() 
							+" Order by "+ dbOrderBy + " collate nocase " + dbDes 
							+ " limit ?" + " offset ?";
				}else{
					strSQL = "select * from " + TABLE_NAME + " where "
							+ getSubCollectQueryKey()
							+" Order by " + dbOrderBy + " " + dbDes + " limit ?"
							+ " offset ?";
				}
				Cursor cursor = this.getDb().rawQuery(strSQL,
												new String[] { 
														folderId, ownerId, getCurrentUserId(),
														String.valueOf(number),
														String.valueOf(count)});
				if (!cursor.moveToFirst()) {
					return fileInfoList;
				}
				do {
					FileInfo fileInfo = new FileInfo();
					fileInfo.fromCursor(cursor);
					fileInfoList.add(fileInfo);
				} while (cursor.moveToNext());
			} catch (Exception e) {
				LogUtil.e(LOG_TAG, "getFileListPage is fail:" + e.getLocalizedMessage());
			}
			return fileInfoList;
		} else {
			LogUtil.e(LOG_TAG, "folderId is null");
		}
		return null;
	}
	
	public HashMap<String, FileInfo> getMappedFileDatas(FileFolderInfo folder) {
		return getMappedFileDatas(folder.getOwnerId(), folder.getId());
	}

	public long getLastUpdateTime(String objectId) {
		return 0;
	}

	public void updateLastUpdateTime(String objectId) {
	}

	@Override
	public void update(FileFolderInfo fileInfo) {
		try {
			String[] whereValue = getQueryValue(fileInfo.getId(), fileInfo.getOwnerBy());
			this.getDb().update(TABLE_NAME, fileInfo.toContentValues(), getQueryKey(), whereValue);
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "updateFile fail:" + e.getLocalizedMessage());
		}
	}

	@Override
	public List<FileInfo> getFileList(String ownerId, String parentID) {
		List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
		try {
			String strSQL = "select * from " + TABLE_NAME + " where " + getSubCollectQueryKey();
			Cursor cursor = this.getDb().rawQuery(strSQL, getQueryValue(parentID, ownerId));
			if(cursor != null) {
				while (cursor.moveToNext()){
					FileInfo fileInfo = new FileInfo();
					fileInfo.fromCursor(cursor);
					fileInfoList.add(fileInfo);
				}
				cursor.close();
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "getFileList fail:" + e.getLocalizedMessage());
		}
		return fileInfoList;
	}

	@Override
	public void updateTransStatus(String ownerId, String id, int transStatus) {
		try {
			if (null != id) {
				ContentValues cv = new ContentValues();
				cv.put(trans_status, transStatus);
				this.getDb().update(TABLE_NAME,cv , getQueryKey(), getQueryValue(id, ownerId));
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "updateTransStatus is fail:" + e.getLocalizedMessage());
		}
	}

	@Override
	public HashMap<String, FileInfo> getMappedFileDatas(String ownerId,
			String folderId) {
		HashMap<String, FileInfo> fileInfoMap = new HashMap<String, FileInfo>();
		Cursor cursor = null;
		try {
			String strSQL = "select * from " + TABLE_NAME + " where " + getSubCollectQueryKey();
			cursor = this.getDb().rawQuery(strSQL, getQueryValue(folderId, ownerId));
			if(cursor != null) {
				while (cursor.moveToNext()) {
					FileInfo fileInfo = new FileInfo();
					fileInfo.fromCursor(cursor);
					fileInfoMap.put(fileInfo.getId(), fileInfo);
				}
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "getFileList fail:" + e.getLocalizedMessage());
		} finally {
			if(cursor != null) {
				cursor.close();
			}
		}
		return fileInfoMap;
	}

	@Override
	public List<FileInfo> getSearchFileList(String ownerId,
			String fileName) {
		List<FileInfo> infoList = new ArrayList<FileInfo>();
		try {
			String sql = "select * from " + TABLE_NAME +" where " 
			+ owner_by +"=? and " + file_name + "=?" +IFileDao.CURRENT_USER_ID+"=?";
			Cursor cursor = this.getDb().rawQuery(sql, new String[] { ownerId ,fileName, getCurrentUserId()});
			if(cursor != null) {
				while(cursor.moveToNext()) {
					FileInfo node = new FileInfo();
					node.fromCursor(cursor);
					infoList.add(node);
				}
				cursor.close();
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "renameFile is fail:" + e.getLocalizedMessage());
		}
		return infoList;
	}

	@Override
	public void rename(FileInfoResponseV2 fileInfoResponse, String name) {
		rename(fileInfoResponse.getOwnerBy(),fileInfoResponse.getId(), fileInfoResponse.getModifiedAt(), name );
	}
	
	@Override
	public void rename(String ownerId, String folderId, long modifyedTime, String name) {
		try {
			if (null != folderId) {
				ContentValues cv = new ContentValues();
				cv.put(file_name, name);
				cv.put(server_mtime, modifyedTime);
				this.getDb().update(TABLE_NAME, cv, getQueryKey(), getQueryValue(folderId, ownerId));
			}
		} catch (Exception e) {
			LogUtil.e(LOG_TAG, "renameFile is fail:" + e.getLocalizedMessage());
		}
	}
	
	/**id=? and owner_by=? and CURRENT_USER_ID=?*/
	private String getQueryKey() {
		return IBaseDao.id + "=? and "+ IBaseDao.owner_by +"=? and " +IFileDao.CURRENT_USER_ID+"=?";
	}

	/**parent_folder_id=? and owner_by=? and CURRENT_USER_ID=?*/
	private String getSubCollectQueryKey() {
		return IBaseDao.parent_folder_id + "=? and "+ IBaseDao.owner_by +"=? and " +IFileDao.CURRENT_USER_ID+"=?";
	}
	
	private String[] getQueryValue(String folderId, String ownerId) {
		return new String[] { folderId , ownerId, getCurrentUserId()};
	}

	private String getCurrentUserId() {
		return ShareDriveApplication.getInstance().getWnerID();
	}

	@Override
	public void syncFileInfoToLocal(FileFolderInfo info) {
		if (null != info) {
			//sync serverMD5 to localMD5
			info.setLocalIdentity(info.getIdentity());
			//sync database
			this.getDb().update(TABLE_NAME, info.getIdentityCV(), getQueryKey(), 
					getQueryValue(info.getId(), info.getOwnerBy()));
		}
	}
}
